﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Data;
using System.Data.Common;
using DataModels.Common;
using DataModels.Enumerations;

namespace GenericTools.Models
{
    /// <summary>
    /// Enumeration of known systems for extracting or sending data
    /// </summary>
    public enum OtherKnownSystem
    {
        /// <summary>
        /// PEPFAR Reporting Online Management Information System
        /// </summary>
        PROMIS = 1,

        /// <summary>
        /// District Health Information System Version 2
        /// </summary>
        DHIS2 = 2
    }

    /// <summary>
    /// Represents other system which can be used to extract or send data.
    /// </summary>
    public class OtherSystem
    {
        #region Constants
        private const int PROMIS_ID = 1;
        private const int DHIS2_ID = 2;
        #endregion

        #region Variables
        private int _Id;
        private string _Name;
        private string _Description;
        private bool _ProvidesFacilityUniqueIdentifier;
        #endregion

        #region Public Properties
        public int Id
        {
            get { return _Id; }
            set { _Id = value; }
        }

        public string Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        public string Description
        {
            get { return _Description; }
            set { _Description = value; }
        }

        public bool ProvidesFacilityUniqueIdentifier
        {
            get { return _ProvidesFacilityUniqueIdentifier; }
            set { _ProvidesFacilityUniqueIdentifier = value; }
        }
        #endregion

        #region Constructors
        private OtherSystem(DataRow row)
        {
            Id = int.Parse(row["Id"].ToString());
            Name = row["Name"].ToString();
            Description = row["Description"].ToString();
            ProvidesFacilityUniqueIdentifier = bool.Parse(row["ProvidesFacilityUniqueIdentifier"].ToString());
        }
        #endregion

        public static OtherSystem GetOtherSystem(int systemId)
        {
            DataTable dataTable = Utilities.GetOtherSystem(systemId);
            if (dataTable.Rows.Count == 1)
            {
                DataRow row = dataTable.Rows[0];
                var system = new OtherSystem(row);
                return system;
            }
            else return null;
        }

        public static OtherSystem GetOtherSystem(OtherKnownSystem knownSystem)
        {
            int id = 0;
            if (knownSystem == OtherKnownSystem.PROMIS) id = PROMIS_ID;
            if (knownSystem == OtherKnownSystem.DHIS2) id = DHIS2_ID;

            DataTable dataTable = Utilities.GetOtherSystem(id);
            if (dataTable.Rows.Count == 1)
            {
                DataRow row = dataTable.Rows[0];
                var system = new OtherSystem(row);
                return system;
            }
            else return null;
        }

        public static List<OtherSystem> GetOtherSystems()
        {
            var systems = new List<OtherSystem>();

            DataTable dataTable = Utilities.GetOtherSystems();
            foreach (DataRow row in dataTable.Rows)
            {
                var system = new OtherSystem(row);                
                systems.Add(system);
            }
            return systems;
        }

        public static bool SaveOtherSystemDetails(int systemId, string internalFacilityCode, string facilityCode, 
            string facilityName, string districtName, string regionName, int userId)
        {
            string checkQuery = @"SELECT COUNT(*) FROM OtherSystemsFacilityDetails
                WHERE SystemId=@SystemId AND InternalFacilityCode=@InternalFacilityCode";
            
            string insertQuery = @"INSERT INTO OtherSystemsFacilityDetails(SystemId, InternalFacilityCode,
                FacilityCode, FacilityName, DistrictName, RegionName) VALUES(@SystemId, @InternalFacilityCode,
                @FacilityCode, @FacilityName, @DistrictName, @RegionName)";
            
            string updateQuery = @"UPDATE OtherSystemsFacilityDetails SET FacilityCode=@FacilityCode, 
                FacilityName=@FacilityName, DistrictName=@DistrictName, RegionName=@RegionName
                WHERE SystemId=@SystemId AND InternalFacilityCode=@InternalFacilityCode";

            DbCommand command = null;
            switch (AppConfiguration.AccessMethod)
            {
                case DataAccessMethod.DIRECT_ACCESS:
                case DataAccessMethod.OFFLINE_DIRECT_ACCESS:
                    command = GenericDataAccess.CreateCommand();
                    break;

                case DataAccessMethod.OFFLINE_DATA_ACCESS:
                    command = GenericDataAccess.CreateCacheDBCommand();
                    break;

                case DataAccessMethod.WEB_SERVICES:
                    var webService = new IQServices.IQService();
                    webService.Url = AppConfiguration.WebServiceURL;
                    string userSignature = DataTransformation.Encrypt(userId.ToString());
                    string output = webService.SaveOtherSystemDetails(systemId, internalFacilityCode, facilityCode,
                        facilityName, districtName, regionName, userSignature);
                    bool saved = bool.Parse(DataTransformation.Decrypt(output));
                    return saved;
            }

            command.CommandType = CommandType.Text;
            DbParameter param = command.CreateParameter();
            param.ParameterName = "@FacilityCode";
            param.DbType = DbType.String;
            param.Value = facilityCode;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@FacilityName";
            param.DbType = DbType.String;
            param.Value = facilityName;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@DistrictName";
            param.DbType = DbType.String;
            param.Value = districtName;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@RegionName";
            param.DbType = DbType.String;
            param.Value = regionName;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@SystemId";
            param.DbType = DbType.Int32;
            param.Value = systemId;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@InternalFacilityCode";
            param.DbType = DbType.String;
            param.Value = internalFacilityCode;
            command.Parameters.Add(param);

            command.CommandText = checkQuery;
            int count = int.Parse(GenericDataAccess.ExecuteScalar(command, false));
            if (count == 1)
            {
                command.CommandText = updateQuery;
                count = GenericDataAccess.ExecuteNonQuery(command, true);
                return (count == 1);
            }

            if (count == 0)
            {
                command.CommandText = insertQuery;
                count = GenericDataAccess.ExecuteNonQuery(command, true);
                return (count == 1);
            }

            return false;
        }
    }
}
